package cn.andev.app.morsesignal;

import java.util.ArrayList;
import java.util.HashMap;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.TabActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.Typeface;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View.OnCreateContextMenuListener;
import android.view.View.OnFocusChangeListener;
import android.view.MotionEvent;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.EditText;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.SimpleAdapter;
import android.widget.TabHost;
import android.widget.TabWidget;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.TabHost.OnTabChangeListener;

import com.admob.android.ads.*;
import com.mobclix.android.sdk.MobclixAdView;
import com.mobclix.android.sdk.MobclixAdViewListener;
import com.mobclix.android.sdk.MobclixIABRectangleMAdView;
import com.mobclix.android.sdk.MobclixMMABannerXLAdView;

public class MorseSignal extends Activity {
	private static final String TAG = "MorseSignal";
	
	private static final float MINIMUM_BACKLIGHT = 0.f;
	private static final float MAXIMUM_BACKLIGHT = 1.0f;

	public static final int MODE_MAIN = -1;
	private static final int MODE_FLASHLIGHT = 0;
	private static final int MODE_FLASH = 1;
	private static final int MODE_SOS = 2;	
	private static final int MODE_ILOVEU = 3;	
	private static final int MODE_CUSTOM = 6;	
	private static final int MODE_ABOUT = 7;
	public static final int MODE_CONFIG = 9;
		
	private PowerManager.WakeLock mWakeLock;
	
	private int mOldBrightness;
	private View mWindow;
	
	private LinearLayout mLinearLayout;
	
	private static MediaPlayer mpLong = new MediaPlayer();//play for -
	private static MediaPlayer mpShort = new MediaPlayer();//play for .
	
	/**
	 * background color
	 * 
	 * 1: white
	 * 0: black
	 */
	private int mFlag;
	
	/**
	 * -1: main
	 * 0: flashlight
	 * 1: flash
	 * 2: sos
	 * 3: I love U
	 * 4: custom message
	 */
	public static int mCurrentMode = MODE_MAIN;
	private Handler gHandler;
	
	// -----------------------------------
	private FlashHandler mFlashHandler;
	
	// -----------------------------------
	private SOSHandler mSOSHandler;
	private int mSOSIdx;
	
	// -----------------------------------
	private ILoveUHandler mILoveUHandler;
	private int mILoveUIdx;
	
	// -----------------------------------
	private CustomHandler mCustomHandler;
	private int mCustomIdx;
	private TabHost mTabHost;
	
	// ----------------------------------- for CustomEdit tab
	public static SQLiteContext db;
	private static final String DATABASE_NAME = "morsesignal.db";
	private static final String MSG_TABLE_NAME = "t_msg";
	private static final String CONFIG_TABLE_NAME = "t_config";
	public static int[] mCustomCode = new int[]{};
	private EditText editBoxTitle;
	private EditText editBoxMsg;
	private Cursor curMsg;
	private Cursor curConfig;
	
	// ----------------------------------- context menu
	private static final int CONTEXTMENU_ITEM_DELETE = 0;
	//private static final int CONTEXTMENU_ITEM_EDIT = 1;
	//private static final int CONTEXTMENU_ITEM_COPY = 2;
	
	//
	MobclixMMABannerXLAdView adview_banner;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		if(!isOkAndroidVersion()){
			Toast.makeText(MorseSignal.this, "Not supported version of Android", Toast.LENGTH_SHORT).show();
			finish();
			return;			
		}
		
		initMain();
	}
	
	private void initMain(){
		setContentView(R.layout.main);
		
		mTabHost = (TabHost)findViewById(R.id.mainwindow);
		mTabHost.setup();
	    
	    mTabHost.addTab(mTabHost.newTabSpec("tabUsual").setIndicator("Usual").setContent(R.id.usualUse));
	    mTabHost.addTab(mTabHost.newTabSpec("tabCustom").setIndicator("Custom").setContent(R.id.customEdit));
	    mTabHost.addTab(mTabHost.newTabSpec("tabRef").setIndicator("Ref").setContent(R.id.ref));
	    
	    mTabHost.setOnTabChangedListener(new OnTabChangeListener() {
            @Override 
            public void onTabChanged(String tabTag) {
                changeTab(mTabHost.getCurrentTab()); 
            } 
        });
	    
	    mTabHost.setCurrentTab(0);
		
		mOldBrightness = getOldBrightness();
		
		setFullscreen();
		
		//mWindow = findViewById(R.id.mainwindow);
		
		mWakeLock = getWakeLock();
		
		// create MediaPlayer
		//MediaPlayer mpLong = MediaPlayer.create(MorseSignal.this, R.raw.l);
		//MediaPlayer mpShort = MediaPlayer.create(MorseSignal.this, R.raw.s);
		
		initUsualTab();
		initCustomEdit();
		
		mCurrentMode = MODE_MAIN;
		
		// Prepare for mobclix
		adview_banner = (MobclixMMABannerXLAdView) findViewById(R.id.advertising_banner_view);  
        adview_banner.setRefreshTime(8000);  
        adview_banner.getAd();
	}
	
	private void initUsualTab(){
		findViewById(R.id.flashlighting).setOnClickListener(new View.OnClickListener() {  
		    public void onClick(View v) {
		    	mCurrentMode = MODE_FLASHLIGHT;
		    	modeFlashlight();
		    }  
		});
		findViewById(R.id.flash).setOnClickListener(new View.OnClickListener() {  
		    public void onClick(View v) {
		    	mCurrentMode = MODE_FLASH;
		    	modeFlash();		    	
		    }  
		});  
		findViewById(R.id.iLoveU).setOnClickListener(new View.OnClickListener() {  
		    public void onClick(View v) {
		    	mCurrentMode = MODE_ILOVEU;
		    	modeILoveU();
		    }  
		});  
		findViewById(R.id.SOS).setOnClickListener(new View.OnClickListener() {  
		    public void onClick(View v) {
		    	mCurrentMode = MODE_SOS;
		    	modeSOS();
		    }  
		});
		
		// Change background image when focus changes
		findViewById(R.id.flashlighting).setOnTouchListener(new OnTouchListener() {
	      public boolean onTouch(View v, MotionEvent event) {
	    	  ImageView imageview = (ImageView)findViewById(v.getId());
	    	  int eventaction = event.getAction();
	    	  switch (eventaction) {
	    	  	case MotionEvent.ACTION_OUTSIDE:
	    	  	case MotionEvent.ACTION_UP:
	    	  		imageview.setImageResource(R.drawable.bulb128x128_bw);
	    	  		mCurrentMode = MODE_FLASHLIGHT;
			    	modeFlashlight();
	    	  		break;
	    	  	default:
	    	  		imageview.setImageResource(R.drawable.bulb128x128);
	    	  		break;
	    	  }
	    	  return true;
	      }
	    });
		findViewById(R.id.flash).setOnTouchListener(new OnTouchListener() {
			public boolean onTouch(View v, MotionEvent event) {
			    ImageView imageview = (ImageView)findViewById(v.getId());
			    int eventaction = event.getAction();
		      	switch (eventaction) {
	    	  	case MotionEvent.ACTION_OUTSIDE:
	    	  	case MotionEvent.ACTION_UP:
	    	  		imageview.setImageResource(R.drawable.lighting128x128_bw);
	    	  		mCurrentMode = MODE_FLASH;
			    	modeFlash();
	    	  		break;
	    	  	default:
	    	  		imageview.setImageResource(R.drawable.lighting128x128);
	    	  		break;
	    	  }
	    	  return true;
		    }
	    });
		findViewById(R.id.iLoveU).setOnTouchListener(new OnTouchListener() {
			public boolean onTouch(View v, MotionEvent event) {
			    ImageView imageview = (ImageView)findViewById(v.getId());
			    int eventaction = event.getAction();
		      	switch (eventaction) {
	    	  	case MotionEvent.ACTION_OUTSIDE:
	    	  	case MotionEvent.ACTION_UP:
	    	  		imageview.setImageResource(R.drawable.love128x128_bw);
	    	  		mCurrentMode = MODE_ILOVEU;
			    	modeILoveU();
	    	  		break;
	    	  	default:
	    	  		imageview.setImageResource(R.drawable.love128x128);
	    	  		break;
	    	  }
	    	  return true;
		    }
	    });
		findViewById(R.id.SOS).setOnTouchListener(new OnTouchListener() {
			public boolean onTouch(View v, MotionEvent event) {
			    ImageView imageview = (ImageView)findViewById(v.getId());
			    int eventaction = event.getAction();
		      	switch (eventaction) {
	    	  	case MotionEvent.ACTION_OUTSIDE:
	    	  	case MotionEvent.ACTION_UP:
	    	  		imageview.setImageResource(R.drawable.help128x128_bw);
	    	  		mCurrentMode = MODE_SOS;
			    	modeSOS();
	    	  		break;
	    	  	default:
	    	  		imageview.setImageResource(R.drawable.help128x128);
	    	  		break;
	    	  }
	    	  return true;
		    }
	    });
	}
	
	private void initCustomEdit(){
		editBoxTitle = (EditText) findViewById(R.id.inputCustomTitle);
		editBoxMsg = (EditText) findViewById(R.id.inputCustomMsg);
		
		//init db
		db = new SQLiteContext(MorseSignal.this, DATABASE_NAME, MSG_TABLE_NAME, CONFIG_TABLE_NAME);
				
		// when OK clicked, show tip "save or not?", then flash it 
		final ImageButton btnOK = (ImageButton) findViewById(R.id.btnOK);
		btnOK.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                // build dialog
                ifSaveToDBRightnow();            	
            	ifFlashCustomMsgRightnow();
            }
        });
		
		// click 'Cancel' to leave to main  
		final ImageButton btnCancel = (ImageButton) findViewById(R.id.btnCancel);
		btnCancel.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
            	if(db.isOpen()) db.close();
            	mTabHost.setCurrentTab(0);
            }
        });
		
		// click 'Clear' to clear content  
		final ImageButton btnClear = (ImageButton) findViewById(R.id.btnClear);
		btnClear.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
            	editBoxTitle.setText("");
            	editBoxMsg.setText("");
            	editBoxTitle.setHint(R.string.titlehint);
            	editBoxMsg.setHint(R.string.msghint);
            }
        });
		
		// Save to SQLite
		final ImageButton btnSave = (ImageButton) findViewById(R.id.btnSave);
		btnSave.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
            	if(editBoxTitle.getText().toString().length()==0){
            		Toast.makeText(MorseSignal.this, "Please make a title", Toast.LENGTH_SHORT).show();
            		return;
            	}
            	if(editBoxMsg.getText().toString().length()==0){
            		Toast.makeText(MorseSignal.this, "Write something about message", Toast.LENGTH_SHORT).show();
            		return;
            	}
            	
            	// db connection
    			if(!db.openDB()){
    				Toast.makeText(MorseSignal.this, "fail to open db", Toast.LENGTH_SHORT).show();
    				return;
    			}
            	
            	if(db.saveMsg(editBoxTitle.getText().toString(), editBoxMsg.getText().toString())) {
            		// save success: show popup tip "message saved"
            		Toast.makeText(MorseSignal.this, "message saved", Toast.LENGTH_SHORT).show();
            		// clear the content in title and message EditText
            		editBoxTitle.clearComposingText();
            		editBoxMsg.clearComposingText();
            		editBoxTitle.findFocus();
            	} else {
            		// save failure: show popup tip "save failed"
            		Toast.makeText(MorseSignal.this, "save failed", Toast.LENGTH_SHORT).show();
            	}
            	db.close();
            }
        });
		
		// List all saved messages
		final ImageButton btnList = (ImageButton) findViewById(R.id.btnList);
		btnList.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
            	listSavedMsg();
            }
        });
	}
	
	//ask if save custom msg to DB right now
	private void ifSaveToDBRightnow(){
		new AlertDialog.Builder(MorseSignal.this)
    	.setTitle("Want to")
    	.setMessage("Save it before flash?")
    	.setIcon(R.drawable.save32x32)
    	.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
    		public void onClick(DialogInterface dialog, int whichButton) {
    			setResult(RESULT_OK);
            	// db connection
    			if(!db.openDB()){
    				Toast.makeText(MorseSignal.this, "fail to open db", Toast.LENGTH_SHORT).show();
    				return;
    			}
    			// save to DB
    			if(db.saveMsg(editBoxTitle.getText().toString(), editBoxMsg.getText().toString())) {
    				Toast.makeText(MorseSignal.this, "message saved", Toast.LENGTH_SHORT).show();
                	// clear the content in title and message EditText
                	editBoxTitle.clearComposingText();
                	editBoxMsg.clearComposingText();
                	editBoxTitle.findFocus();
                } else {
                	// save failure: show popup tip "save failed"
                	Toast.makeText(MorseSignal.this, "save failed", Toast.LENGTH_SHORT).show();
                }
                db.close();
    		}
    	})
    	.setNegativeButton("No", new DialogInterface.OnClickListener() {
    		public void onClick(DialogInterface dialog, int whichButton) {
    			setResult(RESULT_CANCELED);
    		}
    	})
    	.show();
	}
	
	// ask if flash custom msg right now
	private void ifFlashCustomMsgRightnow() {
		new AlertDialog.Builder(MorseSignal.this)
		.setTitle("Want to")
		.setMessage("Flash it right now?")
		.setIcon(R.drawable.bulb32x32)
		.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int whichButton) {
				setResult(RESULT_OK);
				// flash it right now
				mCurrentMode = MODE_CUSTOM;
				mCustomCode = MorseCode.encodeCustomMsg(editBoxMsg.getText().toString());
				modeCustomMsg();
			}
		})
		.setNegativeButton("No", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int whichButton) {
				setResult(RESULT_CANCELED);
			}
		})
		.show();
	}
	
	private void listSavedMsg(){
		// db connection
		if(!db.openDB()){
			Toast.makeText(MorseSignal.this, "fail to open db", Toast.LENGTH_SHORT).show();
			return;
		}
		
		// list all saved msg
		ListView list = (ListView) findViewById(R.id.listmsgview);  
		ArrayList<HashMap<String, Object>> listItem = new ArrayList<HashMap<String, Object>>();
		curMsg = db.loadAllMsgs();
		
		while(curMsg.moveToNext()){
			HashMap<String, Object> map = new HashMap<String, Object>();  
            //map.put("ItemImage", R.drawable.checked);
            map.put("ItemTitle", curMsg.getString(1));  
            map.put("ItemText", curMsg.getString(2));  
            listItem.add(map);    		    		
    	}    	
		SimpleAdapter listItemAdapter = new SimpleAdapter(MorseSignal.this, listItem,   
	            R.layout.list_items,	                      
	            new String[] {"ItemImage", "ItemTitle", "ItemText"},
	            new int[] {R.id.ItemTitle, R.id.ItemText}//R.id.ItemImage,  
	    );
      
		list.setAdapter(listItemAdapter); 
		
        list.setOnItemClickListener(new OnItemClickListener() {  
			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
				if(arg2 == 0){
                    mCurrentMode = MODE_CUSTOM;
    				mCustomCode = MorseCode.encodeCustomMsg(((TextView)arg1).getText().toString());
    				modeCustomMsg();
				}
				else if(arg2 == 1)
                    finish();
			}  
        });  
          
        //context menu
        list.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
			@Override
			public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
				menu.setHeaderTitle("Want to");     
                menu.add(0, CONTEXTMENU_ITEM_DELETE, 0, "Delete");
                //menu.add(0, CONTEXTMENU_ITEM_EDIT, 1, "Edit");
                //menu.add(0, CONTEXTMENU_ITEM_COPY, 2, "Copy");
			}
        });
	}
	
	@Override  
    public boolean onContextItemSelected(MenuItem item) {
		AdapterView.AdapterContextMenuInfo info;
        try {
             info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
        } catch (ClassCastException e) {
            Log.e(TAG, "bad menuInfo", e);
            return false;
        }
        
        switch(item.getItemId()){
        	case CONTEXTMENU_ITEM_DELETE: // delete
        		//TODO
        		//String title  = getTitle(info.id);
        		String title = getIntent().getData().getPath();
        		db.deleteMsg(title);
        		return true;
        	//case CONTEXTMENU_ITEM_EDIT: // edit
        		//TODO
        		//return true;
        	default:
        		return super.onContextItemSelected(item);
        }
    }
	
	private void changeTab(int tabId){
        LinearLayout ll=(LinearLayout)mTabHost.getChildAt(0); 
        TabWidget tw=(TabWidget)ll.getChildAt(0);
        int tabCount=tw.getChildCount();

        for (int i=0;i<tabCount;i++){
        	RelativeLayout rl=(RelativeLayout)tw.getChildAt(i); 
            TextView tv=(TextView)rl.getChildAt(1);
            if (i==tabId){
            	tv.setTypeface(android.graphics.Typeface.create("arial", Typeface.BOLD));
                tv.setTextSize(20f);
            }
        }
    }
	
	protected boolean isOkAndroidVersion()  {
		String  currentSdkVersion = Build.VERSION.SDK;
		if(Integer.parseInt(currentSdkVersion) >=3 ) 
			return true;
		else 
			return false;
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		menu.add(0, MODE_ABOUT, 0, "About").setIcon(android.R.drawable.ic_dialog_info);// about menu
		menu.add(0, MODE_CONFIG, 0, "Config").setIcon(R.drawable.config32x32);// config menu
		return  super.onCreateOptionsMenu(menu);
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {		
		//mCurrentMode = item.getItemId();
		
		//setContentView(R.layout.nothing);
		//mWindow = findViewById(R.id.nothingwindow);
		
		switch (item.getItemId()) {
		case MODE_ABOUT:
			modeAbout();
			return true;
		case MODE_CONFIG:
			modeConfig();
			return true;
		}
		
		return super.onOptionsItemSelected(item);
	}
	
	@Override
	protected void onStop() {
		restoreBrightness();
		mWakeLock.release();
		
		super.onStop();
	}

	// ---------------------------------------------------------------------------- Dark
	private void modeDark() {
		mFlag = 0;
		mWindow.setBackgroundColor(Color.BLACK);
		setBrightness(MINIMUM_BACKLIGHT);
	}
	
	// ---------------------------------------------------------------------------- Config
	public void modeConfig() {
		startActivity(new Intent(MorseSignal.this, Config.class));
	}
	
	// ---------------------------------------------------------------------------- About
	public void modeAbout() {
		setContentView(R.layout.nothing);
		mWindow.setBackgroundColor(Color.BLACK);
		restoreBrightness();
		new AlertDialog.Builder(MorseSignal.this)
        .setIcon(android.R.drawable.ic_dialog_info)
        .setTitle("About")
        .setMessage(R.string.app_about)
        .setPositiveButton(R.string.OK, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
            	restoreToMain();
            }
        })
        .create().show();		
	}
	
	// ---------------------------------------------------------------------------- Flashlight	
	public void modeFlashlight() {
		setContentView(R.layout.nothing);
		mWindow = findViewById(R.id.nothingwindow);
		
		mFlag = 1;
		mWindow.setBackgroundColor(Config.color);
		setBrightness(MAXIMUM_BACKLIGHT);
	}
	
	// ---------------------------------------------------------------------------- Flash
	public void modeFlash() {
		setContentView(R.layout.nothing);
		mWindow = findViewById(R.id.nothingwindow);
		mWindow.setBackgroundColor(Config.color);
		
		mFlag = 1;
		setBrightness(MAXIMUM_BACKLIGHT);
		mFlashHandler = new FlashHandler();// infinite circulation
		gHandler = mFlashHandler;
		updateFlashUI();
	}
	
	private void updateFlashUI() {		
		if (mCurrentMode != MODE_FLASH) {
			return;
		}
		
		mFlashHandler.sleep(1000);// in sleep(), send a message to call handler after 1
		
		if (mFlag == 1) {
			mWindow.setBackgroundColor(Color.BLACK);
			//setBrightness(MINIMUM_BACKLIGHT);
			mFlag = 0;
		} else {
			mWindow.setBackgroundColor(Config.color);
			//setBrightness(MAXIMUM_BACKLIGHT);
			mFlag = 1;
		}
	}
	
	class FlashHandler extends Handler {
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			MorseSignal.this.updateFlashUI();
		}
		
		public void sleep(long delayMillis) {
			removeMessages(0);			
			sendMessageDelayed(obtainMessage(0), delayMillis);
		}
	}
	
	// ---------------------------------------------------------------------------- SOS
	public void modeSOS() {
		setContentView(R.layout.nothing);
		mWindow = findViewById(R.id.nothingwindow);
		
		mFlag = 1;
		mSOSIdx = 0;
		mSOSHandler = new SOSHandler();
		gHandler = mSOSHandler;
		updateSOSUI();
	}
	
	private void updateSOSUI() {
		if (mCurrentMode != MODE_SOS) {
			return;
		}
		
		mSOSHandler.sleep(MorseCode.mSOSCode[mSOSIdx]);
		
		if (mSOSIdx + 1 == MorseCode.mSOSCode.length) {
			mSOSIdx = 0;
			mFlag = 1;
		} else {
			mSOSIdx++;
		}
		
		if (mFlag == 1) {
			mWindow.setBackgroundColor(Color.BLACK);
			mFlag = 0;
		} else {
			mWindow.setBackgroundColor(Config.color);
			mFlag = 1;
		}
	}
	
	class SOSHandler extends Handler {
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			MorseSignal.this.updateSOSUI();
		}
		
		public void sleep(long delayMillis) {
			removeMessages(0);			
			sendMessageDelayed(obtainMessage(0), delayMillis);
		}
	}
	
	// ---------------------------------------------------------------------------- ILoveU
	public void modeILoveU() {
		setContentView(R.layout.nothing);
		mWindow = findViewById(R.id.nothingwindow);
		
		mFlag = 1;
		mILoveUIdx = 0;
		mILoveUHandler = new ILoveUHandler();
		gHandler = mILoveUHandler;
		updateILoveUUI();
	}
	
	private void updateILoveUUI() {
		if (mCurrentMode != MODE_ILOVEU) {
			return;
		}
		
		mILoveUHandler.sleep(MorseCode.mILoveUCode[mILoveUIdx]);
		
		if (mILoveUIdx + 1 == MorseCode.mILoveUCode.length) {
			mILoveUIdx = 0;
			mFlag = 1;
		} else {
			mILoveUIdx++;
		}
		
		if (mFlag == 1) {
			mWindow.setBackgroundColor(Color.BLACK);
			mFlag = 0;
		} else {
			mWindow.setBackgroundColor(Config.color);
			mFlag = 1;
		}
	}
	
	class ILoveUHandler extends Handler {
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			MorseSignal.this.updateILoveUUI();
		}
		
		public void sleep(long delayMillis) {
			removeMessages(0);			
			sendMessageDelayed(obtainMessage(0), delayMillis);
		}
	}
	
	// ---------------------------------------------------------------------------- Custom
	public void modeCustomMsg() {
		mFlag = 1;
		mCustomIdx = 0;
		mCustomHandler = new CustomHandler();
		gHandler = mCustomHandler;
		updateCustomUI();
	}
	
	private void updateCustomUI() {
		if (mCurrentMode != MODE_CUSTOM) {
			return;
		}
		
		mCustomHandler.sleep(mCustomCode[mCustomIdx]);
		
		if (mCustomIdx + 1 == mCustomCode.length) {
			mCustomIdx = 0;
			mFlag = 1;
		} else {
			mCustomIdx++;
		}
		
		if (mFlag == 1) {
			mWindow.setBackgroundColor(Color.BLACK);
			mFlag = 0;
		} else {
			mWindow.setBackgroundColor(Config.color);
			mFlag = 1;
		}
	}
	
	public class CustomHandler extends Handler {
		private Message _msg;
		
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			MorseSignal.this.updateCustomUI();
		}
		
		public void sleep(long delayMillis) {
			removeMessages(0);			
			sendMessageDelayed(obtainMessage(0), delayMillis);
		}
		
		public void setMsg(Message msg) {
			_msg = msg;
		}
	}
	
	/**
	 * set full screen
	 */
	private void setFullscreen() {
		//requestWindowFeature(Window.FEATURE_NO_TITLE);
		Window win = getWindow();
		win.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
	}
	
	private PowerManager.WakeLock getWakeLock() {
		final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);		
		PowerManager.WakeLock w = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "ExFlashlight");
		w.acquire();		
		return w;
	}
	
	/**
	 * get screen brightness set by current user
	 */
	private int getOldBrightness() {
		int brightness;
		
		try {
			brightness = Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS);
		} catch (SettingNotFoundException snfe) {
			brightness = 100;//MAXIMUM_BACKLIGHT;
		}
		
		return brightness;
	}
	
	/**
	 * restore original screen brightness
	 */
	private void restoreBrightness() {
		setBrightness(mOldBrightness);
	}
	
	/**
	 * set screen brightness
	 */
	private void setBrightness(float brightness) {
		/* deprecated in Android 1.5 : cannot use IHardwareService to change screen brightness
		 * link : http://www.javaeye.com/topic/412807
		IHardwareService hardware = IHardwareService.Stub.asInterface(ServiceManager.getService("hardware"));

		if (hardware != null) {
			try {
				hardware.setScreenBacklight(brightness);
			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}*/
	    WindowManager.LayoutParams lp = getWindow().getAttributes();  
	    lp.screenBrightness = brightness;
	    getWindow().setAttributes(lp);  
	}
	
	@Override  
	public boolean onKeyDown(int keyCode,KeyEvent event) {  
	    // back key 
	    if (keyCode == KeyEvent.KEYCODE_BACK) {
	    	if(mCurrentMode == MODE_MAIN){
	    		// exit program
	            MorseSignal.this.finish();
	    	} else {
	    		restoreToMain();
	    	}
	    	return true;
	    } else // if not back key  
	        return super.onKeyDown(keyCode, event);		  
	}
	
	protected void restoreToMain(){
    	if(gHandler != null) gHandler.removeMessages(0);
    	restoreBrightness();
    	
    	initMain();
	}
}